// xp_impersonatehandles.cpp
// -------------
// Extended stored procedure for testing named pipe impersonation.

#include "xp_impersonatehandles.h"

BOOL APIENTRY DllMain(HMODULE hModule,DWORD  ul_reason_for_call,LPVOID lpReserved)
{
	switch (ul_reason_for_call)
	{
	case DLL_PROCESS_ATTACH:
	case DLL_THREAD_ATTACH:
	case DLL_THREAD_DETACH:
	case DLL_PROCESS_DETACH:
		break;
	}
	return TRUE;
}

// Versioning export
__declspec(dllexport) ULONG __GetXpVersion()
{
   return ODS_VERSION;
}

// Added for xp_loadlibrary() usage
__declspec(dllexport) bool xp_impersonatehandleslib(SRV_PROC *srvproc, TCHAR* tcParameters)
{
	// Call the original xsproc and report the success/failure
	if(XP_NOERROR == xp_impersonatehandles(srvproc))
		return(true);
	else
		return(false);
}

// Xsproc entry point
__declspec(dllexport) SRVRETCODE xp_impersonatehandles(SRV_PROC *srvproc)
{
	HANDLE			hThread = NULL;
	HANDLE			hToken = NULL;
	DWORD			dwFlags = 0;
	DWORD			dwGapCounter = 0;
	DWORD			dwType = 0;
	DWORD			dwTypeSize = 0;
	DWORD			dwTokenAccess = 0;
	DWORD			dwRequiredSize = 0;
	TOKEN_USER*		pTokenUser = NULL;
	TCHAR			tcClient[256];
	TCHAR			tzUserName[MAX_PATH];
	DWORD			dwNsize = MAX_PATH;
	TCHAR			tzDomainName[MAX_PATH];
	DWORD			dwDsize = MAX_PATH;
	SID_NAME_USE	snuSNU; // Death by?
	TCHAR*			pTempUser = NULL;

	for(DWORD dwCounter = 1; dwCounter < 0x7fffffff; dwCounter++)
	{
		// Check to see if it's a valid handle
		if(0 != GetHandleInformation((void*)dwCounter,&dwFlags))
		{
			dwTypeSize = sizeof(DWORD);
			// Check to see if it's a socket
			if(0 == getsockopt((SOCKET)dwCounter,SOL_SOCKET,SO_TYPE,(char*)&dwType,(int*)&dwTypeSize))
			{
				if(SOCK_STREAM == dwType)
				{
					
					//if(0 == WSAImpersonateSocketPeer(    .....    you get the idea
				}
			}
			else
			{
				// Check to see if it's a named pipe
				if(0 != GetNamedPipeClientComputerName((HANDLE)dwCounter,tcClient,sizeof(tcClient)))
				{
					hThread = GetCurrentThread();

					// Valid named pipe, attempt impersonation
					if(0 != ImpersonateNamedPipeClient((HANDLE)dwCounter));
					{
						// Impersonation was successful, get the token information
						dwTokenAccess = TOKEN_ALL_ACCESS;
						if(OpenThreadToken(hThread,dwTokenAccess,FALSE,&hToken))
						{
							GetTokenInformation(hToken,TokenUser,NULL,0,&dwRequiredSize);
							pTokenUser = (PTOKEN_USER) new BYTE[dwRequiredSize];
							memset(pTokenUser,0,dwRequiredSize);
							if(GetTokenInformation(hToken,TokenUser,pTokenUser,dwRequiredSize,&dwRequiredSize))
							{
								// Get the user information for the current token
								if(LookupAccountSid(NULL,pTokenUser->User.Sid,tzUserName,&dwNsize,tzDomainName,&dwDsize,&snuSNU))
								{
									// Create the DOMAIN\User string
									pTempUser = new TCHAR[_tcslen(tzDomainName) + _tcslen(_T("Impersonated: \\")) + _tcslen(tzUserName) + 1];
									_stprintf(pTempUser,_T("Impersonated: %s\\%s"),tzDomainName,tzUserName);

									// Report the findings back to SQL as a message
									Sql_SendMsg(srvproc,pTempUser);

									delete [] pTempUser;
									memset(tzUserName,0,MAX_PATH);
									memset(tzDomainName,0,MAX_PATH);
									delete [] pTokenUser;
								}

								CloseHandle(hToken);
								CloseHandle(hThread);
							}
							else
							{
								delete [] pTokenUser;
								CloseHandle(hToken);
								CloseHandle(hThread);
							}
						}
						else
						{
							CloseHandle(hThread);
						}
						RevertToSelf();
					}
				}
			}
			dwGapCounter = 0;
		}
		else
			dwGapCounter++;

		if(10000 == dwGapCounter)
		{
			// Gap threshold hit, probably nothing valid beyond here
			break;
		}
	}

	return(XP_NOERROR);
}

// Send a SQL msg (non-error)
SRVRETCODE Sql_SendMsg(SRV_PROC *srvproc,TCHAR* tczMsg)
{
	int	iResult = 0;
	// Both the ASCII and UNICODE calls are assuming a NULL terminated string
#ifdef UNICODE
	// wcslen() is used here because 'SRV_NULLTERM' seems to always result in FAILURE with srv_wsendmsg()
	iResult = srv_wsendmsg(srvproc,(DBTINYINT)0,(DBTINYINT)0,tczMsg,wcslen(tczMsg));//SRV_NULLTERM);
#else
	iResult = srv_sendmsg(srvproc, SRV_MSG_INFO, 0,(DBTINYINT)0,(DBTINYINT)0,NULL,0,0,tczMsg,strlen((CHAR*)tczMsg));
#endif
	if(iResult != SUCCEED)
		return(Sql_SendErr(srvproc,_T("Sql_SendMsg failure.")));
	return(SUCCEED);
}

// Send a SQL msg (error)
SRVRETCODE Sql_SendErr(SRV_PROC *srvproc,TCHAR* tczErr)
{
	int	iResult = 0;
	// Both the ASCII and UNICODE calls are assuming a NULL terminated string
#ifdef UNICODE
	// wcslen() is used here because 'SRV_NULLTERM' seems to always result in FAILURE with srv_wsendmsg()
	iResult = srv_wsendmsg(srvproc,0,SRV_MSG_ERROR,tczErr,wcslen(tczErr));//SRV_NULLTERM);
#else
	iResult = srv_sendmsg(srvproc, SRV_MSG_ERROR, 0,(DBTINYINT)0,(DBTINYINT)0,NULL,0,0,tczErr,strlen((CHAR*)tczErr));
#endif
	if(SUCCEED != iResult)
		return(FAIL);
	return(SUCCEED);
}